
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       task_logger.c
  * @author     baiyang
  * @date       2021-8-7
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include <stdbool.h>
#include <string.h>
#include <rtthread.h>

#include "task_logger.h"

#include <common/grapilot.h>
#include <common/console/console.h>
#include <file_manager/file_manager.h>
#include <logger/blog.h>

#include <board_config/borad_config.h>
/*-----------------------------------macro------------------------------------*/
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL_WIN
#define MAX_LOG_SESSION_NUM 1000
#else
#define MAX_LOG_SESSION_NUM 100
#endif

#define LOG_SESSION_FOLDER  "/log"
#define LOG_SESSION_ID_FILE "session_id.txt"

/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/

/*----------------------------------variable----------------------------------*/
static char thread_logger_stack[2048];
struct rt_thread thread_logger_handle;

static char* logger_tag = "[logger]";
static uint16_t _log_session_id = 0;
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
static gp_err _get_log_session(char* session);

static gp_err _create_log_session(void)
{
    char session_name[100];

    if (_get_log_session(session_name) != GP_EOK) {
        return GP_ERROR;
    }

    // if exist, delete it first
    if (fs_file_exist(session_name)) {
        if (fs_deldir(session_name) != GP_EOK) {
            console_printf("%s fail to delete %s, errno:%d\n", logger_tag, session_name, rt_get_errno());
            return GP_ERROR;
        }
    }

    // create log session
    if (mkdir(session_name, 0x777) < 0) {
        console_printf("%s fail to create %s, errno:%d\n", logger_tag, session_name, rt_get_errno());
        return GP_ERROR;
    }

    return GP_EOK;
}

static gp_err _get_log_session(char* session)
{
    if (_log_session_id == 0)
        return GP_ERROR;

    sprintf(session, "%s/session_%d", LOG_SESSION_FOLDER, _log_session_id);

    return GP_EOK;
}

static uint16_t _update_log_session_id(bool create_new)
{
    int fd;
    int ret;
    uint16_t id = 0;
    char file_name[50] = {0};
    char id_buffer[6];

    DIR *dirp = opendir(LOG_SESSION_FOLDER);

    if (dirp == RT_NULL)
    {
        /* 创建目录 */
        ret = mkdir(LOG_SESSION_FOLDER, 0x777);
        if (ret < 0)
        {
            /* 创建目录失败 */
            console_printf("%s dir error!\n", logger_tag);
        }
        else
        {
            /* 创建目录成功 */
            console_printf("%s mkdir ok!\n", logger_tag);
        }
    }

    snprintf(file_name, sizeof(file_name), "%s/%s", LOG_SESSION_FOLDER, LOG_SESSION_ID_FILE);

    if (fs_file_exist(file_name)) {
        fd = open(file_name, O_RDONLY);

        if (fd < 0) {
            goto Out;
        }

        int rb = read(fd, id_buffer, 5);

        if (rb < 0) {
            goto Out;
        }

        // check if is valid number
        for (uint8_t i = 0; i < rb; i++) {
            if (id_buffer[i] < '0' || id_buffer[i] > '9') {
                goto Out;
            }
        }

        id_buffer[rb] = '\0';
        id = atoi(id_buffer);
    } else if (create_new) {
        // create a new session id file
        fd = open(file_name, O_CREAT | O_WRONLY);

        if (fd < 0) {
            goto Out;
        }

        id = 0;

        console_printf("%s create session_id.txt\n", logger_tag);
    } else {
        id = 0;
        goto Out;
    }

    if (fd)
        close(fd);

    // update id
    id = id % MAX_LOG_SESSION_NUM;
    id++;

    sprintf(file_name, "%s/%s", LOG_SESSION_FOLDER, LOG_SESSION_ID_FILE);
    fd = open(file_name, O_TRUNC | O_WRONLY);

    if (fd < 0) {
        console_printf("%s fail to update log session id\n", logger_tag);
        id = 0;
        goto Out;
    }

    fs_fprintf(fd, "%d", id);

Out:

    if (fd) {
        close(fd);
    }

    return id;
}

void get_working_log_session(char* path)
{
    sprintf(path, "%s/session_%d", LOG_SESSION_FOLDER, _log_session_id);
}

gp_err logger_start_blog(char* path)
{
    char log_name[100];
    static uint8_t blog_id = 0;

    if (path) {
        /* if a valid path is provided, use it for blog */
        return blog_start(path);
    }

    if (_log_session_id == 0) {
        console_printf("%s no available log session\n", logger_tag);
        return GP_ERROR;
    }

    sprintf(log_name, "%s/session_%d/blog%d.bin", LOG_SESSION_FOLDER, _log_session_id, ++blog_id);

    return blog_start(log_name);
}

void logger_stop_blog(void)
{
    blog_stop();
}

void task_logger_entry(void* parameter)
{
    while (1) {
        blog_async_output();
        rt_thread_mdelay(10);
    }
}

gp_err task_logger_init(void)
{
    rt_err_t res;

    /* init binary log */
    blog_init();

    /* get log session id */
    _log_session_id = _update_log_session_id(true);

    if (_log_session_id == 0 || _log_session_id > MAX_LOG_SESSION_NUM) {
        console_printf("%s wrong log session id:%d\n", logger_tag, _log_session_id);
    } else {
        _create_log_session();
    }

    if (blog_get_log_mode() == 2) {
        logger_start_blog(NULL);
    }

    res = rt_thread_init(&thread_logger_handle,
                           "logger",
                           task_logger_entry,
                           RT_NULL,
                           &thread_logger_stack[0],
                           sizeof(thread_logger_stack),PRIORITY_LOGGER,5);

    RT_ASSERT(res == RT_EOK);

    if (res == RT_EOK) {
        rt_thread_startup(&thread_logger_handle);
    }

    brd_set_vehicle_init_stage(INIT_STAGE_LOGGER);

    return GP_EOK;
}

/*------------------------------------test------------------------------------*/


